﻿/*
*    Qizx/open 3.0 beta
*
* This code is the open-source version of Qizx.
* Copyright (C) 2004-2009 Axyana Software -- All rights reserved.
*
* The contents of this file are subject to the Mozilla Public License 
*  Version 1.1 (the "License"); you may not use this file except in 
*  compliance with the License. You may obtain a copy of the License at
*  http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
*  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
*  for the specific language governing rights and limitations under the
*  License.
*
* The Initial Developer of the Original Code is Xavier Franc - Axyana Software.
*
*/
using System;
using DataModelException = System.Qizx.Api.DataModelException;
using EvaluationException = System.Qizx.Api.EvaluationException;
using BasicNode = System.Qizx.Xdm.BasicNode;
using EvalContext = System.Qizx.XQuery.EvalContext;
using Focus = System.Qizx.XQuery.Focus;
using XQValue = System.Qizx.XQuery.XQValue;
using System.Qizx.XQuery.Dt;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Qizx.XQuery.Op {
    class ApplyExpr : Expression {
        Expression[] exprs = new Expression[0];
        bool updating;

        public ApplyExpr() {
        }

        public void addExpr(Expression expr) {
            exprs = addExpr(exprs, expr);
        }

        Expression getExpr(int rank) {
            return rank < 0 || rank >= exprs.Length ? null : exprs[rank];
        }

        public override Expression Child(int rank) {
            return (rank < exprs.Length) ? exprs[rank] : null;
        }

        public int getFlags() {
            return updating ? UPDATING : 0;
        }

        public void dump(ExprDisplay d) {
            d.header(this);
            d.children("exprs", exprs);
        }

        public Expression staticCheck(ModuleContext context, int flags) {
            int nupCount = 0;
            type = exprs.Length == 0 ? XQType.NONE.opt : null;
            for (int e = 0, E = exprs.Length; e < E; e++) {
                Expression subx = exprs[e] = context.simpleStaticCheck(exprs[e], 0);
                if (type == null) {
                    type = subx.getType();
                } else {
                    // System.err.println("union "+type+" avec
                    // "+exprs[e].getType());
                    type = type.unionWith(subx.getType(), false);
                    // System.err.println("donne "+type);
                }
                if (type == null)
                    context.error("(BUG)", subx, "no union type found");

                if (UpdatingExpr.isUpdating(subx))
                    updating = true;
                else if (!UpdatingExpr.isVacuous(subx))
                    ++nupCount;
            }
            return this;
        }

        public bool isVacuous() {
            if (exprs == null || exprs.Length == 0)
                return true;
            for (int c = 0, C = exprs.Length; c < C; c++) {
                if (!UpdatingExpr.isVacuous(exprs[c]))
                    return false;
            }
            return true;
        }

        public XQValue eval(Focus focus, EvalContext context) {
            XQValue last = null;    // at least one subexpr anyway
            for (int c = 0, C = exprs.Length; c < C; c++) {
                last = exprs[c].eval(focus, context);
                // actually expand the sequence here
                ArraySequence expanded = new ArraySequence(4, last);
                for (; last.Next(); )
                    expanded.addItem(last.Item);
                last = expanded;
                // TODO apply updates
            }
            return last;
        }
    }
}
